package com.ruoyi.web.controller.minio;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 构建操作minio的服务类
 *
 * @author tzx
 */
@Service
@Slf4j
public class MinIoService {
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfiguration configuration;


    /**
     * 获取上传文件临时签名，作用是：前端获取到签名信息后可以直接将文件上传到minio
     *
     * @param fileName
     * @param time
     * @return
     */
    public Map getPolicyUrl(String fileName, ZonedDateTime time) {
        PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
        postPolicy.addEqualsCondition("key", fileName);
        try {
            Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
            HashMap<String, String> policyMap = new HashMap<>();
            map.forEach((k, v) -> {
                policyMap.put(k.replaceAll("-", ""), v);
            });
            policyMap.put("host", configuration.getUrl() + "/" + configuration.getBucketName());
            return policyMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param objectName
     * @param time
     * @param timeUnit
     * @return
     */
    public String getFileUrl(String objectName, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(configuration.getBucketName())
                .object(objectName)
                .expiry(time, timeUnit).build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 针对前端直接上传的是文件的格式
     *
     * @param file 文件
     */
    public void uploadToFile(MultipartFile file) {
        // 使用putObject上传一个文件到存储桶中。
        try {
            InputStream inputStream = file.getInputStream();
            String fileName = file.getOriginalFilename();
            log.info("上传的文件名为：{}", fileName);
            minioClient.putObject(PutObjectArgs.builder()
                .bucket(configuration.getBucketName())
                .object(fileName.substring(0, fileName.indexOf(".")))
                .stream(inputStream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据文件名访问指定有效期的文件访问链接
     *
     * @param objectName
     * @param time
     * @param timeUnit
     * @return
     */
    public String getUrl(String objectName, int time, TimeUnit timeUnit) {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(configuration.getBucketName())
                .object(objectName)
                .expiry(time, timeUnit).build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return url;
    }

    /**
     * 实现上传图片到Minio
     */
    public String upload(MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        String bucketName = "admin";
//        String endpoint = "http://10.52.3.63:9000";
        String endpoint = "http://47.100.189.93:9000";
//        String endpoint = "http://127.0.0.1:9000";
        // 检查存储桶是否已经存在
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (isExist) {
            System.out.println("Bucket already exists.");
        } else {
            // 创建一个名为 huike-crm 的存储桶，用于存储照片的zip文件。
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }

        // 避免文件覆盖 生成日期文件夹格式+文件 ：年/月/日 + 文件名
        //获取原始文件名
        String originalFilename = file.getOriginalFilename();
        if (!originalFilename.contains("\\.")) {
            originalFilename = "." + originalFilename;
        }
        //拼接生成新的UUID形式的文件名
        String objectName = new SimpleDateFormat("yyyy/MM/dd/").format(new Date()) + UUID.randomUUID().toString()
            .replaceAll("-", "")
            + originalFilename.substring(originalFilename.lastIndexOf("."));
        //2.通过Minio对象将图片上传到minio桶中
        // 使用putObject上传一个文件到存储桶中。
        PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
            .bucket(bucketName)
            .contentType(file.getContentType())
            .stream(file.getInputStream(), file.getSize(), -1).build();
        minioClient.putObject(objectArgs);

        //组装桶中文件的访问url
        String resUrl = endpoint + "/" + bucketName + "/" + objectName;
        return resUrl;
    }
}

